#pragma once

#include <iostream>
#include <vector>
#include <pthread.h>
#include "Sem.hpp"

template<class T>
class RingQueue
{
public:
    RingQueue(int num = 5)
        :_v(num)
        ,_num(num)
        ,c_step(0)
        ,p_step(0)
        ,space_sem(num)
        ,data_sem(0)
    {
        pthread_mutex_init(&_clock, nullptr);
        pthread_mutex_init(&_plock, nullptr);
    }

    void push(const T& in) // 生产者: 推送任务
    {
        space_sem.V();  // 先申请信号量
        pthread_mutex_lock(&_plock);  // 上锁

        // 推送任务
        _v[p_step++] = in;
        p_step %= _num;

        pthread_mutex_unlock(&_plock); // 解锁
        data_sem.P();  // P操作 释放信号量
    }

    void pop(T& out)  // 消费者：拿取数据
    {
        data_sem.V();   // 先申请信号量
        pthread_mutex_lock(&_clock);  // 先上锁
        
        // 拿取任务
        out = _v[c_step++];
        c_step %= _num; 

        pthread_mutex_unlock(&_clock); // 解锁
        space_sem.P();  // P操作,释放信号量
    }

    ~RingQueue()
    {
        pthread_mutex_destroy(&_clock);
        pthread_mutex_destroy(&_plock);
    }
private:
    std::vector<T> _v;  // 用数组来模拟环形队列
    int _num;  // 环形队列的容量
    int c_step; // 消费者的位置
    int p_step; // 生产者的位置
    Sem space_sem;  // 表示生产空间
    Sem data_sem;   // 表示消费空间
    pthread_mutex_t _clock; // 消费者的锁
    pthread_mutex_t _plock; // 生产者的锁
};